package mx.vlabs.soapdroid.wsdl2java;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import mx.vlabs.soapdroid.utils.Utils;

import org.ow2.easywsdl.schema.api.ComplexType;
import org.ow2.easywsdl.schema.api.Element;
import org.ow2.easywsdl.schema.api.SimpleType;
import org.ow2.easywsdl.schema.api.Type;

public class ElementAttributes extends HashMap<String, Object>{
	
	private static String MAX_OCCURS_UNBOUNDED = "unbounded";
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public ElementAttributes() {
		super();
		// TODO Auto-generated constructor stub
	}

	public ElementAttributes(int initialCapacity, float loadFactor) {
		super(initialCapacity, loadFactor);
		// TODO Auto-generated constructor stub
	}

	public ElementAttributes(int initialCapacity) {
		super(initialCapacity);
		// TODO Auto-generated constructor stub
	}

	public ElementAttributes(Map<? extends String, ? extends Object> m) {
		super(m);
		// TODO Auto-generated constructor stub
	}

	public static List<ElementAttributes> explode(Type type){
		
		if(type instanceof ComplexType)
			return explode((ComplexType)type);
		else if(type instanceof SimpleType)
			return explode((SimpleType)type);
		else 
			return new ArrayList<ElementAttributes>();
		
	}
	
    public static List<ElementAttributes> explode(ComplexType complexType){
    	
    	
		List<ElementAttributes> attributesList = new ArrayList<ElementAttributes>();
		
		
		if(complexType.getSequence()!=null)
		for(Element element: complexType.getSequence().getElements()){
			ElementAttributes attrs = new ElementAttributes();
			attrs.putAll(defaults());
			attrs.put("nillable", element.isNillable());
			
			if(element.getMaxOccurs().equals(MAX_OCCURS_UNBOUNDED))
				attrs.put("list", true);
			
			attrs.put("type",element.getType().getQName());
			attrs.put("name", element.getQName());
			attrs.put("complex", element.getType() instanceof ComplexType);
			
			attrs.put("javaType", getJavaType(attrs));
			attrs.put("javaElementType", getJavaType(attrs,false));
			attrs.put("javaName", getJavaName(attrs));
			
			attributesList.add(attrs);
		}
		
		return attributesList;
	}
    
    
    
    public ElementAttributes rename(String newName){
    		this.put("javaName", SDroidUtils.buildJavaName(newName));
    		return this;
    }
    
    public static List<ElementAttributes> explode(SimpleType simpleType){
    	
    	
		List<ElementAttributes> attributesList = new ArrayList<ElementAttributes>();
		
		ElementAttributes attrs = new ElementAttributes();
		attrs.putAll(defaults());
		
		attrs.put("type",simpleType.getQName());
		attrs.put("name", simpleType.getQName());
		attrs.put("complex", false);
		attrs.put("javaType", getJavaType(attrs));
		attrs.put("javaElementType", getJavaType(attrs,false));
		attrs.put("javaName", getJavaName(attrs));
		
		attributesList.add(attrs);
		
		
		return attributesList;
	}
    
    public static ElementAttributes explodeSingle(SimpleType simpleType){
    	
		ElementAttributes attrs = new ElementAttributes();
		attrs.putAll(defaults());
		
		attrs.put("type",simpleType.getQName());
		attrs.put("name", simpleType.getQName());
		attrs.put("complex", false);
		attrs.put("javaType", getJavaType(attrs));
		attrs.put("javaElementType", getJavaType(attrs,false));
		attrs.put("javaName", getJavaName(attrs));
		

		return attrs;
	}
    
    private static String getJavaType(ElementAttributes attrs){
    	return getJavaType(attrs, (Boolean) attrs.get("list"));
    }
    
    private static String getJavaName(ElementAttributes attrs){
    	return SDroidUtils.buildJavaName(((QName) attrs.get("name")).getLocalPart());
    }
    
    private static String getJavaType(ElementAttributes attrs, boolean isList){
    	
    	StringBuilder sb = new StringBuilder();
    	
    	if(isList){
    		sb.append("java.util.List<");
    		sb.append(getJavaType(attrs, false));
    		sb.append(">");
    	}else{
    		
    		if((Boolean) attrs.get("complex")){
    			sb.append(Utils.capitalizeFirstLetter(((QName)attrs.get("type")).getLocalPart()));
    		}else{
    			sb.append(getJavaSimpleType(attrs));
    		}
    		
    	}
    	
    	return sb.toString();
    }
    
    private static String getJavaSimpleType(ElementAttributes attrs){
    	
    	QName name = (QName) attrs.get("type");
    	
    	String localPart = name.getLocalPart();
    	
    	if(localPart.equals("string"))
    		return "String";
    	else if(localPart.equals("int"))
    		return "Integer";
    	else if(localPart.equals("long"))
    		return "Long";
    	else if(localPart.equals("double"))
    		return "Double";
    	else if(localPart.equals("float"))
    		return "Float";
    	else if(localPart.equals("char"))
    		return "Character";
    	else if(localPart.equals("dateTime"))
    		return "java.util.Date";
    	else if(localPart.equals("base64Binary"))
    		return "Byte[]";
    	else if(localPart.equals("anyType"))
    		return "Object";
    	else
    		return Utils.capitalizeFirstLetter(name.getLocalPart());
    }
    
    private static ElementAttributes defaults(){
    	
    	ElementAttributes attrs = new ElementAttributes();
    	attrs.put("list", false);
		attrs.put("nillable", true);
		
		return attrs;
    }

}
